#include "oled.h"
#include "i2c.h"

// OLED显存
static uint8_t OLED_GRAM[OLED_WIDTH][OLED_PAGES];

// 函数声明
static uint32_t OLED_Pow(uint8_t m, uint8_t n);

// 6x8 ASCII字体
static const uint8_t ASCII_6x8[][6] = {
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // sp
    {0x00, 0x00, 0x00, 0x2f, 0x00, 0x00}, // !
    {0x00, 0x00, 0x07, 0x00, 0x07, 0x00}, // "
    {0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14}, // #
    {0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12}, // $
    {0x00, 0x62, 0x64, 0x08, 0x13, 0x23}, // %
    {0x00, 0x36, 0x49, 0x55, 0x22, 0x50}, // &
    {0x00, 0x00, 0x05, 0x03, 0x00, 0x00}, // '
    {0x00, 0x00, 0x1c, 0x22, 0x41, 0x00}, // (
    {0x00, 0x00, 0x41, 0x22, 0x1c, 0x00}, // )
    {0x00, 0x14, 0x08, 0x3E, 0x08, 0x14}, // *
    {0x00, 0x08, 0x08, 0x3E, 0x08, 0x08}, // +
    {0x00, 0x00, 0x00, 0xA0, 0x60, 0x00}, // ,
    {0x00, 0x08, 0x08, 0x08, 0x08, 0x08}, // -
    {0x00, 0x00, 0x60, 0x60, 0x00, 0x00}, // .
    {0x00, 0x20, 0x10, 0x08, 0x04, 0x02}, // /
    {0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E}, // 0
    {0x00, 0x00, 0x42, 0x7F, 0x40, 0x00}, // 1
    {0x00, 0x42, 0x61, 0x51, 0x49, 0x46}, // 2
    {0x00, 0x21, 0x41, 0x45, 0x4B, 0x31}, // 3
    {0x00, 0x18, 0x14, 0x12, 0x7F, 0x10}, // 4
    {0x00, 0x27, 0x45, 0x45, 0x45, 0x39}, // 5
    {0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30}, // 6
    {0x00, 0x01, 0x71, 0x09, 0x05, 0x03}, // 7
    {0x00, 0x36, 0x49, 0x49, 0x49, 0x36}, // 8
    {0x00, 0x06, 0x49, 0x49, 0x29, 0x1E}, // 9
    {0x00, 0x00, 0x36, 0x36, 0x00, 0x00}, // :
    {0x00, 0x00, 0x56, 0x36, 0x00, 0x00}, // ;
    {0x00, 0x08, 0x14, 0x22, 0x41, 0x00}, // <
    {0x00, 0x14, 0x14, 0x14, 0x14, 0x14}, // =
    {0x00, 0x00, 0x41, 0x22, 0x14, 0x08}, // >
    {0x00, 0x02, 0x01, 0x51, 0x09, 0x06}, // ?
    {0x00, 0x32, 0x49, 0x59, 0x51, 0x3E}, // @
    {0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C}, // A
    {0x00, 0x7F, 0x49, 0x49, 0x49, 0x36}, // B
    {0x00, 0x3E, 0x41, 0x41, 0x41, 0x22}, // C
    {0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C}, // D
    {0x00, 0x7F, 0x49, 0x49, 0x49, 0x41}, // E
    {0x00, 0x7F, 0x09, 0x09, 0x09, 0x01}, // F
    {0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A}, // G
    {0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F}, // H
    {0x00, 0x00, 0x41, 0x7F, 0x41, 0x00}, // I
    {0x00, 0x20, 0x40, 0x41, 0x3F, 0x01}, // J
    {0x00, 0x7F, 0x08, 0x14, 0x22, 0x41}, // K
    {0x00, 0x7F, 0x40, 0x40, 0x40, 0x40}, // L
    {0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F}, // M
    {0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F}, // N
    {0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E}, // O
    {0x00, 0x7F, 0x09, 0x09, 0x09, 0x06}, // P
    {0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E}, // Q
    {0x00, 0x7F, 0x09, 0x19, 0x29, 0x46}, // R
    {0x00, 0x46, 0x49, 0x49, 0x49, 0x31}, // S
    {0x00, 0x01, 0x01, 0x7F, 0x01, 0x01}, // T
    {0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F}, // U
    {0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F}, // V
    {0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F}, // W
    {0x00, 0x63, 0x14, 0x08, 0x14, 0x63}, // X
    {0x00, 0x07, 0x08, 0x70, 0x08, 0x07}, // Y
    {0x00, 0x61, 0x51, 0x49, 0x45, 0x43}, // Z
    {0x00, 0x00, 0x7F, 0x41, 0x41, 0x00}, // [
    {0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55}, // 55
    {0x00, 0x00, 0x41, 0x41, 0x7F, 0x00}, // ]
    {0x00, 0x04, 0x02, 0x01, 0x02, 0x04}, // ^
    {0x00, 0x40, 0x40, 0x40, 0x40, 0x40}, // _
    {0x00, 0x00, 0x01, 0x02, 0x04, 0x00}, // '
    {0x00, 0x20, 0x54, 0x54, 0x54, 0x78}, // a
    {0x00, 0x7F, 0x48, 0x44, 0x44, 0x38}, // b
    {0x00, 0x38, 0x44, 0x44, 0x44, 0x20}, // c
    {0x00, 0x38, 0x44, 0x44, 0x48, 0x7F}, // d
    {0x00, 0x38, 0x54, 0x54, 0x54, 0x18}, // e
    {0x00, 0x08, 0x7E, 0x09, 0x01, 0x02}, // f
    {0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C}, // g
    {0x00, 0x7F, 0x08, 0x04, 0x04, 0x78}, // h
    {0x00, 0x00, 0x44, 0x7D, 0x40, 0x00}, // i
    {0x00, 0x40, 0x80, 0x84, 0x7D, 0x00}, // j
    {0x00, 0x7F, 0x10, 0x28, 0x44, 0x00}, // k
    {0x00, 0x00, 0x41, 0x7F, 0x40, 0x00}, // l
    {0x00, 0x7C, 0x04, 0x18, 0x04, 0x78}, // m
    {0x00, 0x7C, 0x08, 0x04, 0x04, 0x78}, // n
    {0x00, 0x38, 0x44, 0x44, 0x44, 0x38}, // o
    {0x00, 0xFC, 0x24, 0x24, 0x24, 0x18}, // p
    {0x00, 0x18, 0x24, 0x24, 0x18, 0xFC}, // q
    {0x00, 0x7C, 0x08, 0x04, 0x04, 0x08}, // r
    {0x00, 0x48, 0x54, 0x54, 0x54, 0x20}, // s
    {0x00, 0x04, 0x3F, 0x44, 0x40, 0x20}, // t
    {0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C}, // u
    {0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C}, // v
    {0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C}, // w
    {0x00, 0x44, 0x28, 0x10, 0x28, 0x44}, // x
    {0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C}, // y
    {0x00, 0x44, 0x64, 0x54, 0x4C, 0x44}, // z
    {0x14, 0x14, 0x14, 0x14, 0x14, 0x14}  // horiz lines
};

// OLED写命令
static void OLED_WriteCmd(uint8_t cmd)
{
    uint8_t data[2] = {0x00, cmd}; // 0x00表示写命令
    HAL_I2C_Master_Transmit(&hi2c1, 0x78, data, 2, 100);
}

// OLED写数据
static void OLED_WriteData(uint8_t data)
{
    uint8_t buf[2] = {0x40, data}; // 0x40表示写数据
    HAL_I2C_Master_Transmit(&hi2c1, 0x78, buf, 2, 100);
}

// OLED初始化
void OLED_Init(void)
{
    HAL_Delay(100);
    
    // 初始化命令序列
    OLED_WriteCmd(0xAE); // 关闭显示
    OLED_WriteCmd(0xD5); // 设置时钟分频因子,震荡频率
    OLED_WriteCmd(0x80); // [3:0],分频因子;[7:4],震荡频率
    OLED_WriteCmd(0xA8); // 设置驱动路数
    OLED_WriteCmd(0x3F); // 默认0X3F(1/64) 
    OLED_WriteCmd(0xD3); // 设置显示偏移
    OLED_WriteCmd(0x00); // 默认为0
    OLED_WriteCmd(0x40); // 设置显示开始行 [5:0],行数.
    OLED_WriteCmd(0x8D); // 电荷泵设置
    OLED_WriteCmd(0x14); // bit2，开启/关闭
    OLED_WriteCmd(0x20); // 设置内存地址模式
    OLED_WriteCmd(0x02); // [1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10;
    OLED_WriteCmd(0xA1); // 段重定义设置,bit0:0,0->0;1,0->127;
    OLED_WriteCmd(0xC8); // 设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数
    OLED_WriteCmd(0xDA); // 设置COM硬件引脚配置
    OLED_WriteCmd(0x12); // [5:4]配置
    OLED_WriteCmd(0x81); // 对比度设置
    OLED_WriteCmd(0xEF); // 1~255;默认0X7F
    OLED_WriteCmd(0xD9); // 设置预充电周期
    OLED_WriteCmd(0xf1); // [3:0],PHASE 1;[7:4],PHASE 2;
    OLED_WriteCmd(0xDB); // 设置VCOMH 电压倍率
    OLED_WriteCmd(0x30); // [6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;
    OLED_WriteCmd(0xA4); // 全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
    OLED_WriteCmd(0xA6); // 设置显示方式;bit0:1,反相显示;0,正常显示
    OLED_WriteCmd(0xAF); // 开启显示
    
    OLED_Clear();
}

// 清屏函数
void OLED_Clear(void)
{
    uint8_t i, n;
    for(i = 0; i < OLED_PAGES; i++)
    {
        OLED_WriteCmd(0xb0 + i);
        OLED_WriteCmd(0x00);
        OLED_WriteCmd(0x10);
        for(n = 0; n < OLED_WIDTH; n++)
        {
            OLED_WriteData(0x00);
            OLED_GRAM[n][i] = 0x00;
        }
    }
}

// 开启OLED显示
void OLED_DisplayOn(void)
{
    OLED_WriteCmd(0x8D);
    OLED_WriteCmd(0x14);
    OLED_WriteCmd(0xAF);
}

// 关闭OLED显示
void OLED_DisplayOff(void)
{
    OLED_WriteCmd(0x8D);
    OLED_WriteCmd(0x10);
    OLED_WriteCmd(0xAE);
}

// 设置颜色模式
void OLED_SetColorMode(OLED_ColorMode mode)
{
    if(mode == OLED_COLOR_NORMAL)
        OLED_WriteCmd(0xA6);
    else
        OLED_WriteCmd(0xA7);
}

// 设置点
void OLED_SetPixel(uint8_t x, uint8_t y, OLED_ColorMode color)
{
    uint8_t pos, bx, temp = 0;
    if(x > OLED_WIDTH - 1 || y > OLED_HEIGHT - 1) return;
    pos = y / 8;
    bx = y % 8;
    temp = 1 << bx;
    if(color == OLED_COLOR_NORMAL)
        OLED_GRAM[x][pos] |= temp;
    else
        OLED_GRAM[x][pos] &= ~temp;
}

// 显示字符串
void OLED_PrintString(uint8_t x, uint8_t y, char *str, OLED_ColorMode color)
{
    uint8_t j = 0;
    while(str[j] != '\0')
    {
        if(x > OLED_WIDTH - 6)
        {
            x = 0;
            y++;
        }
        if(y > OLED_PAGES - 1) return;
        
        uint8_t c = str[j] - ' ';
        for(uint8_t i = 0; i < 6; i++)
        {
            uint8_t temp = ASCII_6x8[c][i];
            for(uint8_t k = 0; k < 8; k++)
            {
                if(temp & 0x01)
                    OLED_SetPixel(x + i, y * 8 + k, color);
                temp >>= 1;
            }
        }
        x += 6;
        j++;
    }
}

// 显示数字
void OLED_PrintNum(uint8_t x, uint8_t y, uint32_t num, uint8_t len, OLED_ColorMode color)
{
    uint8_t t, temp;
    uint8_t enshow = 0;
    for(t = 0; t < len; t++)
    {
        temp = (num / OLED_Pow(10, len - t - 1)) % 10;
        if(enshow == 0 && t < (len - 1))
        {
            if(temp == 0)
            {
                OLED_PrintString(x + 6 * t, y, " ", color);
                continue;
            }
            else
                enshow = 1;
        }
        OLED_PrintString(x + 6 * t, y, (char*)(temp + '0'), color);
    }
}

// 显示帧
void OLED_ShowFrame(void)
{
    uint8_t i, n;
    for(i = 0; i < OLED_PAGES; i++)
    {
        OLED_WriteCmd(0xb0 + i);
        OLED_WriteCmd(0x00);
        OLED_WriteCmd(0x10);
        for(n = 0; n < OLED_WIDTH; n++)
        {
            OLED_WriteData(OLED_GRAM[n][i]);
        }
    }
}

// 辅助函数：计算10的幂
static uint32_t OLED_Pow(uint8_t m, uint8_t n)
{
    uint32_t result = 1;
    while(n--)
        result *= m;
    return result;
} 
